Skip to content

feat(multimodal): CUDA-graph bucket ladder (Dynamo-side target_bucket) + Qwen3-VL ViT example#11039

Closed
furionw wants to merge 1 commit into
qiwa/vision-encoder-batcherfrom
qiwa/vision-encoder-cuda-graphs
Closed

feat(multimodal): CUDA-graph bucket ladder (Dynamo-side target_bucket) + Qwen3-VL ViT example#11039
furionw wants to merge 1 commit into
qiwa/vision-encoder-batcherfrom
qiwa/vision-encoder-cuda-graphs

Conversation

@furionw

@furionw furionw commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Summary

PR4 of 4 in the custom vision-encoder series, stacked on PR3 (#11037).
Introduces bucket-wise graph support on the Dynamo side and a real graphed
encoder example. buckets / target_bucket were defined-but-unused since PR1;
this PR makes them live.

What's here

  • ThreadedMicroBatcher gains an optional buckets ladder. When set, the batcher rounds a batch's packed sum(cost) up to the nearest rung and passes it as target_bucket to fn(items, target_bucket). _validate_buckets requires max(buckets) >= max_batch_cost. buckets=None stays eager (target_bucket=None) — PR3 behavior is unchanged.
  • AsyncVisionEncoder passes backend.buckets to the batcher.
  • Qwen3VLViTEncoder example — loads the real Qwen3-VL vision tower, captures one CUDA graph per rung via torch.compile(reduce-overhead) in build(), and in forward_batch pads sum(cost) up to target_bucket (whole dummy images), replays that rung's graph, and slices the real images back out (one tensor per item, input order). This is vLLM's EncoderCudaGraphManager scheme — a bounded ladder + pad-to-rung, deliberately not SGLang's per-exact-shape capture.

The author owns padding; Dynamo only picks the rung.

Test plan

  • Batcher target_bucket rounding: exact-rung, sub-rung → next rung, eager None, and the max(buckets) >= max_batch_cost validation.
  • Graph smoke (validated on the integration branch): ladder [256, 512, 1024, 2048, 4096]; a 5-image batch (cost 1280) padded to the 2048 rung (3 dummy images), replayed, and sliced back to 5 (256, hidden) tensors — GRAPH_SMOKE_OK.

Known limitation

Qwen3-VL injects per-layer deepstack features that the one-tensor-per-image
contract does not carry, so this example exercises the encoder + batcher + graph
mechanism, not Qwen3-VL accuracy. A contract extension for deepstack-style
auxiliary features is future work.

Note

Based on the series' validated merge-base; rebase onto main before merge.

Stacked series

PR1 (contract) → PR2 (eager, no batcher) → PR3 (ThreadedMicroBatcher) → PR4 (this).

🤖 Generated with Claude Code

@furionw furionw temporarily deployed to external_collaborator June 29, 2026 04:55 — with GitHub Actions Inactive
@github-actions github-actions Bot added feat backend::vllm Relates to the vllm backend multimodal labels Jun 29, 2026
@datadog-official

datadog-official Bot commented Jun 29, 2026

Copy link
Copy Markdown

Pipelines

⚠️ Warnings

🚦 1 Pipeline job failed

Docs link check | lychee   View in Datadog   GitHub Actions

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: fc9b5d2 | Docs | Give us feedback!

…) + Qwen3-VL ViT example

PR4 of the custom vision-encoder series, stacked on PR3. Introduces bucket-wise
graph support on the Dynamo side and a real graphed encoder example.

- ThreadedMicroBatcher: optional `buckets` ladder. When set, the batcher rounds a
  batch's packed sum(cost) UP to the nearest rung and passes it as `target_bucket`
  to fn(items, target_bucket). With max_batch_cost=None it derives the ceiling as
  max(buckets); buckets=None stays eager / pass-through (PR3 behavior unchanged).
- AsyncVisionEncoder passes backend.buckets to the batcher.
- Qwen3VLViTEncoder example: loads the real Qwen3-VL vision tower (build(model_id),
  picks its own device), captures one CUDA graph per rung via
  torch.compile(reduce-overhead), and in forward_batch pads sum(cost) up to
  target_bucket, replays, slices the real images back out (CPU). Hardcodes
  image_token_id via the Qwen base.

The author owns padding; Dynamo only picks the rung. `buckets`/`target_bucket`
were forward-compat in the contract since PR1; this PR makes them live.

Tests: target_bucket rounding (boundary + eager None + buckets-derive +
ladder-covers-budget). Graph smoke validated on the integration branch.

Deepstack limitation: Qwen3-VL deepstack features are not carried by the
one-tensor-per-image contract — this exercises the mechanism, not accuracy.

Note: based on the series' validated merge-base; rebase onto main before merge.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@furionw furionw force-pushed the qiwa/vision-encoder-batcher branch from 729398f to 4f361b7 Compare June 30, 2026 17:08
@furionw furionw force-pushed the qiwa/vision-encoder-cuda-graphs branch from aa90a19 to fc9b5d2 Compare June 30, 2026 17:08
@furionw

furionw commented Jun 30, 2026

Copy link
Copy Markdown
Contributor Author

we don't need this feature for now as it's not requested

@furionw furionw closed this Jun 30, 2026
@furionw furionw deleted the qiwa/vision-encoder-cuda-graphs branch July 8, 2026 00:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant